#pragma once

#include "basechart_base.h"

class S_WIDGETS_EXPORT BaseChartPainter : public QPainter {
  Q_GADGET
 public:
  /*!
    Defines special modes the painter can operate in. They disable or enable
    certain subsets of features/fixes/workarounds, depending on whether they are
    wanted on the respective output device.
  */
  enum PainterMode {
    pmDefault =
        0x00  ///< <tt>0x00</tt> Default mode for painting on screen devices
    ,
    pmVectorized =
        0x01  ///< <tt>0x01</tt> Mode for vectorized painting (e.g. PDF export).
              ///< For example, this prevents some antialiasing fixes.
    ,
    pmNoCaching = 0x02  ///< <tt>0x02</tt> Mode for all sorts of exports (e.g.
                        ///< PNG, PDF,...). For example, this prevents using
                        ///< cached pixmap labels
    ,
    pmNonCosmetic =
        0x04  ///< <tt>0x04</tt> Turns pen widths 0 to 1, i.e. disables cosmetic
              ///< pens. (A cosmetic pen is always drawn with width 1 pixel in
              ///< the vector image/pdf viewer, independent of zoom.)
  };
  Q_ENUMS(PainterMode)
  Q_FLAGS(PainterModes)
  Q_DECLARE_FLAGS(PainterModes, PainterMode)

  BaseChartPainter();
  explicit BaseChartPainter(QPaintDevice* device);

  // getters:
  bool antialiasing() const { return testRenderHint(QPainter::Antialiasing); }
  PainterModes modes() const { return mModes; }

  // setters:
  void setAntialiasing(bool enabled);
  void setMode(PainterMode mode, bool enabled = true);
  void setModes(PainterModes modes);

  // methods hiding non-virtual base class functions (QPainter bug workarounds):
  bool begin(QPaintDevice* device);
  void setPen(const QPen& pen);
  void setPen(const QColor& color);
  void setPen(Qt::PenStyle penStyle);
  void drawLine(const QLineF& line);
  void drawLine(const QPointF& p1, const QPointF& p2) {
    drawLine(QLineF(p1, p2));
  }
  void save();
  void restore();

  // non-virtual methods:
  void makeNonCosmetic();

 protected:
  // property members:
  PainterModes mModes;
  bool mIsAntialiasing;

  // non-property members:
  QStack<bool> mAntialiasingStack;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(BaseChartPainter::PainterModes)

class S_WIDGETS_EXPORT BaseChartAbstractPaintBuffer {
 public:
  explicit BaseChartAbstractPaintBuffer(const QSize& size,
                                        double devicePixelRatio);
  virtual ~BaseChartAbstractPaintBuffer();

  // getters:
  QSize size() const { return mSize; }
  bool invalidated() const { return mInvalidated; }
  double devicePixelRatio() const { return mDevicePixelRatio; }

  // setters:
  void setSize(const QSize& size);
  void setInvalidated(bool invalidated = true);
  void setDevicePixelRatio(double ratio);

  // introduced virtual methods:
  virtual BaseChartPainter* startPainting() = 0;
  virtual void donePainting() {}
  virtual void draw(BaseChartPainter* painter) const = 0;
  virtual void clear(const QColor& color) = 0;

 protected:
  // property members:
  QSize mSize;
  double mDevicePixelRatio;

  // non-property members:
  bool mInvalidated;

  // introduced virtual methods:
  virtual void reallocateBuffer() = 0;
};

class S_WIDGETS_EXPORT BaseChartPaintBufferPixmap
    : public BaseChartAbstractPaintBuffer {
 public:
  explicit BaseChartPaintBufferPixmap(const QSize& size,
                                      double devicePixelRatio);
  virtual ~BaseChartPaintBufferPixmap() Q_DECL_OVERRIDE;

  // reimplemented virtual methods:
  virtual BaseChartPainter* startPainting() Q_DECL_OVERRIDE;
  virtual void draw(BaseChartPainter* painter) const Q_DECL_OVERRIDE;
  void clear(const QColor& color) Q_DECL_OVERRIDE;

 protected:
  // non-property members:
  QPixmap mBuffer;

  // reimplemented virtual methods:
  virtual void reallocateBuffer() Q_DECL_OVERRIDE;
};

Q_DECLARE_METATYPE(BaseChartPainter::PainterMode)
